/**
 * 数据模型模块
 * 包含游戏状态、单位、建筑、地块等数据模型和命令类
 */

const {
    UnitType,
    BuildingType,
    TildeType,
    EntityType,
    CommandType,
    UNIT_CONFIG,
    BUILDING_CONFIG
} = require('./const');

/**
 * 游戏基础类
 */
class GameBase {
    constructor(jsonObj) {
        this._json = jsonObj;
    }

    toDict() {
        return this._json;
    }

    // 动态属性访问
    get(name) {
        return this._json[name];
    }
}

/**
 * 游戏状态类
 */
class GameState extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.battleId = this._json.battleId;
        this.playerId = this._json['playerId'];
        this.round = this._json['round'];
        this.timeLimit = this._json['timeLimit']; 
        this.battleState = new GameStateModel(this._json['battleState']);
        
        // units - 从所有玩家的 units 对象中收集单位
        this.units = {};
        for (const [playerId, player] of Object.entries(this.battleState.players)) {
            // player.units 是一个对象，键为单位ID，值为UnitModel实例
            if (player.units && typeof player.units === 'object') {
                Object.assign(this.units, player.units);
            }
        }
        
        // buildings - 从所有玩家的 buildings 对象中收集建筑
        this.buildings = {};
        for (const [playerId, player] of Object.entries(this.battleState.players)) {
            // player.buildings 是一个对象，键为建筑ID，值为BuildingModel实例
            if (player.buildings && typeof player.buildings === 'object') {
                Object.assign(this.buildings, player.buildings);
            }
        }
    }

    getMyPlayer() {
        return this.battleState.players[this.playerId];
    }

    getEnemyPlayer() {
        for (const [playerId, player] of Object.entries(this.battleState.players)) {
            if (playerId !== this.playerId) {
                return player;
            }
        }
        return null;
    }

    getUnit(id) {
        return this.units[id] || null;
    }

    getBuilding(id) {
        return this.buildings[id] || null;
    }

    getTilde(x, y) {
        return this.battleState.terrain[y][x] || null;
    }
}

/**
 * 游戏状态模型类
 */
class GameStateModel extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.status = String(this._json.status);
        this.initialized = Boolean(this._json.initialized);
        this.battleEnded = Boolean(this._json.battleEnded);
        this.currentRound = parseInt(this._json.currentRound);
        this.map = this._json['map'];
        this.width = parseInt(this.map['width']);
        this.height = parseInt(this.map['height']);
        
        // terrain
        this.terrain = [];
        for (let i = 0; i < this.map.terrain.length; i++) {
            this.terrain[i] = [];
            for (let j = 0; j < this.map.terrain[i].length; j++) {
                this.terrain[i][j] = new TildeModel(this.map.terrain[i][j]);
            }
        }
        
        // players
        this.players = {};
        for (const [playerId, player] of Object.entries(this._json['players'])) {
            this.players[playerId] = new PlayerInfoModel(player);
        }
    }
}

/**
 * 单位模型类
 */
class UnitModel extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.id = parseInt(this._json['id']);
        this.type = this._json['type'];
        this.hp = parseInt(this._json['hp']);
        this.attack = parseInt(this._json['attack']);
        this.speed = parseInt(this._json['speed']);
        this.position = this._json['position'];
        this.x = parseInt(this.position['x']);
        this.y = parseInt(this.position['y']);
        // config
        this.config = UNIT_CONFIG[this.type] || {};
    }
}

/**
 * 建筑模型类
 */
class BuildingModel extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.id = parseInt(this._json['id']);
        this.type = this._json['type'];
        this.player = String(this._json['player']);
        this.hp = parseInt(this._json['hp']);
        this.attack = parseInt(this._json['attack']);
        this.position = this._json['position'];
        this.x = parseInt(this.position['x']);
        this.y = parseInt(this.position['y']);
        // config
        this.config = BUILDING_CONFIG[this.type] || {};
    }
}

/**
 * 地块模型类
 */
class TildeModel extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.type = this._json['type'];
        this.building = this._json['building'];
        this.unit = this._json['unit'];
        this.player = this._json['player'];
    }
}

/**
 * 玩家信息模型
 */
class PlayerInfoModel extends GameBase {
    constructor(jsonObj) {
        super(jsonObj);
        this.id = String(this._json['id']);
        this.playerType = String(this._json['playerType']);
        this.rmb = parseInt(this._json['rmb']);
        this.baseHealth = parseInt(this._json['baseHealth']);
        
        // units
        this.units = {}
        for (const unit of this._json['units']) {
            if (unit.id) {
                this.units[parseInt(unit.id)] = new UnitModel(unit);
            }
        }
        
        // buildings
        this.baseBuilding = null;
        this.buildings = {};
        for (const building of this._json['buildings']) {
            if (building.id) {
                const obj = new BuildingModel(building);
                this.buildings[parseInt(building.id)] = obj;
                if (obj.type === BuildingType.base) {
                    this.baseBuilding = obj;
                }
            }
        }
    }
}

/**
 * 命令基础类
 */
class CommandBase {
    constructor(input, type, param) {
        const player = input.playerId;
        const round = input.round;
        this._json = {
            type: type,
            player: player,
            round: round,
            param: param
        };
    }

    toDict() {
        return this._json;
    }
}

/**
 * 移动命令类
 */
class MoveCommand extends CommandBase {
    /**
     * 移动命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 单位ID
     * @param {number} x - 目标X坐标
     * @param {number} y - 目标Y坐标
     */
    constructor(input, id, x, y) {
        const unit = input.getUnit(id);
        const offsetX = x - unit.x;
        const offsetY = y - unit.y;
        super(input, CommandType.move, {
            self: {
                type: EntityType.unit,
                utype: unit.type,
                id: id
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

/**
 * 攻击命令类
 */
class AttackCommand extends CommandBase {
    /**
     * 攻击命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 攻击者ID
     * @param {number} targetId - 目标ID
     * @param {number} selfType - 攻击者类型
     * @param {number} targetType - 目标类型
     */
    constructor(input, id, targetId, selfType = EntityType.unit, targetType = EntityType.unit) {
        let attacker, target;
        
        // 攻击者可能是单位也可能是建筑
        if (selfType === EntityType.unit) {
            attacker = input.getUnit(id);
        } else {
            attacker = input.getBuilding(id);
        }
        
        // 攻击目标可能是单位也可能是建筑
        if (targetType === EntityType.unit) {
            target = input.getUnit(targetId);
        } else {
            target = input.getBuilding(targetId);
        }
        
        const offsetX = target.x - attacker.x;
        const offsetY = target.y - attacker.y;
        
        super(input, CommandType.attack, {
            self: {
                type: selfType,
                utype: attacker.type,
                id: id
            },
            target: {
                type: targetType,
                utype: target.type,
                id: targetId
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

/**
 * 建造命令类
 */
class BuildCommand extends CommandBase {
    /**
     * 建造命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 建造者单位ID
     * @param {number} type - 建筑类型
     * @param {number} x - 建造X坐标
     * @param {number} y - 建造Y坐标
     */
    constructor(input, id, type, x, y) {
        const unit = input.getUnit(id);
        const offsetX = x - unit.x;
        const offsetY = y - unit.y;
        
        super(input, CommandType.build, {
            self: {
                type: EntityType.unit,
                utype: unit.type,
                id: id
            },
            target: {
                type: EntityType.building,
                utype: type
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

/**
 * 生产命令类
 */
class SwapCommand extends CommandBase {
    /**
     * 生产命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 建筑ID
     * @param {number} type - 生产单位类型
     * @param {number} x - 生产X坐标
     * @param {number} y - 生产Y坐标
     */
    constructor(input, id, type, x, y) {
        const building = input.getBuilding(id);
        const offsetX = x - building.x;
        const offsetY = y - building.y;
        
        super(input, CommandType.swap, {
            self: {
                type: EntityType.building,
                utype: building.type,
                id: id
            },
            target: {
                type: EntityType.unit,
                utype: type
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

/**
 * 治疗命令类
 */
class HealCommand extends CommandBase {
    /**
     * 治疗命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 治疗单位ID
     * @param {number} targetId - 被治疗单位ID
     */
    constructor(input, id, targetId) {
        const unit = input.getUnit(id);
        const targetUnit = input.getUnit(targetId);
        const offsetX = targetUnit.x - unit.x;
        const offsetY = targetUnit.y - unit.y;
        
        super(input, CommandType.heal, {
            self: {
                type: EntityType.unit,
                utype: unit.type,
                id: id
            },
            target: {
                type: EntityType.unit,
                utype: targetUnit.type,
                id: targetId
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

/**
 * 采集命令类
 */
class CollectCommand extends CommandBase {
    /**
     * 采集命令
     * @param {GameState} input - 游戏状态
     * @param {number} id - 采集者单位ID
     * @param {number} x - 采集X坐标
     * @param {number} y - 采集Y坐标
     */
    constructor(input, id, x, y) {
        const unit = input.getUnit(id);
        const tilde = input.getTilde(x, y);
        const offsetX = x - unit.x;
        const offsetY = y - unit.y;
        
        super(input, CommandType.collect, {
            self: {
                type: EntityType.unit,
                utype: unit.type,
                id: id
            },
            target: {
                type: EntityType.terrain,
                utype: tilde.type
            },
            offsetPosition: {
                x: offsetX,
                y: offsetY
            }
        });
    }
}

module.exports = {
    GameBase,
    GameState,
    GameStateModel,
    UnitModel,
    BuildingModel,
    TildeModel,
    PlayerInfoModel,
    CommandBase,
    MoveCommand,
    AttackCommand,
    BuildCommand,
    SwapCommand,
    HealCommand,
    CollectCommand
};